package com.lslands.controller;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @program: concurrent
 * @Author: lslands
 * @version: v3.0
 * @create: 2021/3/28
 * @description:
 **/
@RestController
public class DemoController {

    @Autowired
    private Redisson redisson;
    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * synchronized  jvm级别的锁 知识和单机环境
     * @return
     */
    @GetMapping("/testDemo")
    public String testDemo(){
        //增加一个synchronized 同步锁，
        synchronized (this){
            //获取库存值
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock>0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock+"");
                System.out.println("扣减成功，剩余："+realStock);
            }else {
                System.out.println("扣减失败");
            }
        }
        return "end";
    }

    /**
     *
     * 出现问题：自己加的锁，可能会被别人释放
     * 实现一个分布式锁
     * @return
     */
    @GetMapping("/testDemo1")
    public String testDemo1(){
        String lockKey = "lockKey";
       /* //redisTemplate.opsForValue().setIfAbsent("lockKey","lslands") == jedis.setnx(k,v)
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey,"lslands");
        //设置一个超时时间，防止宕机情况下出现死锁。  让lockKey这把锁，在redis里面最多存活10秒
        redisTemplate.expire(lockKey,10, TimeUnit.SECONDS);*/
        //原子命令。  防止在设置超时时间之前 ，系统宕机出现死锁的情况
        final Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "lslands", 10, TimeUnit.SECONDS);

        if (!result){
            //此处 ，如果操作失败，就返回，或者等待等。自己处理逻辑
            return "error_code";
        }
        try {
            //获取库存值
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock>0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock+"");
                System.out.println("扣减成功，剩余："+realStock);
            }else {
                System.out.println("扣减失败");
            }
        }finally {
            //finally  代码快一定会被执行
            //释放锁
            redisTemplate.delete(lockKey);
        }




        return "end";
    }



    /**
     * 实现锁续命
     * 实现一个分布式锁
     * @return
     */
    @GetMapping("/testDemo2")
    public String testDemo2(){
        String lockKey = "lockKey";
        //获取锁对象
        RLock  rLock = redisson.getLock(lockKey);
        try {
            //加锁        底层封装了   setIfAbsent(lockKey, "lslands", 10, TimeUnit.SECONDS)
            rLock.lock();
            //获取库存值
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock>0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock+"");
                System.out.println("扣减成功，剩余："+realStock);
            }else {
                System.out.println("扣减失败");
            }
        }finally {
            //解锁
            rLock.unlock();
        }
        return "end";
    }


    /**
     *
     * 提高效率
     * 读锁
     * @return
     */
    @GetMapping("/getDemo")
    public String getDemo(){
        String lockKey = "lockKey";
        //获取锁对象
        RReadWriteLock rReadWriteLock = redisson.getReadWriteLock(lockKey);
        //获取读锁
        RLock  rLock = rReadWriteLock.readLock();
        try {
            //加读锁        底层封装了   setIfAbsent(lockKey, "lslands", 10, TimeUnit.SECONDS)
            rLock.lock();
            //获取库存值
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock>0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock+"");
                System.out.println("扣减成功，剩余："+realStock);
            }else {
                System.out.println("扣减失败");
            }
        }finally {
            //释放读解锁
            rLock.unlock();
        }
        return "end";
    }

    /**
     * 写锁
     * @return
     */
    @GetMapping("/updateDemo")
    public String updateDemo(){
        String lockKey = "lockKey";
        //获取锁对象
        RReadWriteLock rReadWriteLock = redisson.getReadWriteLock(lockKey);
        //获取写锁
        RLock  rLock = rReadWriteLock.writeLock();
        try {
            //加读锁        底层封装了   setIfAbsent(lockKey, "lslands", 10, TimeUnit.SECONDS)
            rLock.lock();
            //获取库存值
            int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));
            if (stock>0){
                int realStock = stock - 1;
                redisTemplate.opsForValue().set("stock",realStock+"");
                System.out.println("扣减成功，剩余："+realStock);
            }else {
                System.out.println("扣减失败");
            }
        }finally {
            //释放读解锁
            rLock.unlock();
        }
        return "end";
    }
}
